﻿/*
 
Celerity: Sensory Overload
Copright 2012 by Adam Hill, David Gannon, Thomas Tamblyn & Patrick Ytting
Contact: adam.hill@outlook.com
Website: adamhill.org
Licence: MS-Pl Licence
  
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Celerity.World.Particles;

namespace Celerity.World
{
	class CollisionDetector
	{
		public List<CollisionRect> rects;
		public CollisionTri player;
		Logic.GameLogic logic;
		ObstacleManager obstacle;
		EmitterFactory emitter;

		public CollisionDetector(
			float playerAngle, 
			float playerZ, 
			float playerWidth, 
			float playerHeight, 
			Tunnel tunnel, 
			ObstacleManager obstacle,
			EmitterFactory emitter,
			Logic.GameLogic logic)
		{
			rects = new List<CollisionRect>();
			player = new CollisionTri(playerAngle, playerZ, playerWidth, playerHeight);
			this.logic = logic;
			tunnel.TunnelSectionSetZCalled += new Tunnel.TunnelSectionSetZCalledHandler(tunnel_TunnelSectionSetZCalled);
			this.obstacle = obstacle;
			this.obstacle.CubeCreated += new ObstacleManager.CubeCreatedHandler(obstacle_CubeCreated);
			this.obstacle.CubeRemoved += new ObstacleManager.CubeRemovedHandler(obstacle_CubeRemoved);
			this.emitter = emitter;
		}

		void obstacle_CubeRemoved(object sender, ObstacleManager.CubeRemovedEventArgs e)
		{
			rects.RemoveAt(e.index);
		}

		void obstacle_CubeCreated(object sender, ObstacleManager.CubeCreatedEventArgs e)
		{
			rects.Add(new CollisionRect(e.tunnelCellSize, e.tunnelNumSegments, e.angle, e.z, e.boxAngleIndex));
		}

		void tunnel_TunnelSectionSetZCalled(object o, Tunnel.TunnelSectionSetZCalledEventArgs e)
		{
			foreach (CollisionRect rect in this.rects)
			{
				if (rect.zUnset)
				{
					rect.SetZ(e.tunnelSection.ZAtStart);
				}
			}
		}

        private void DoCollision(GameTime gameTime)
        {
            // 0 -- 1 - -- +
            // |    | |
            // 2 -- 3 +
            //    0    - -- +
            //  /   \  |
            // 1 --- 2 +
            int boxIndex = -1;
            bool intersected = false;
            for (int i = 0; i < rects.Count; i++)
            {
                CollisionRect rect = rects[i];
                Vector2[] playerBox = new Vector2[4] { new Vector2(player.points[0].X - player.widthOver2, player.points[0].Y), new Vector2(player.points[0].X + player.widthOver2, player.points[0].Y),
                                                                                                                                                                                                   new Vector2(player.points[0].X - player.widthOver2, player.points[1].Y), new Vector2(player.points[0].X + player.widthOver2, player.points[1].Y) };

                if (rect.boxPositionIndex == 9 && player.points[2].X > (float)(Math.PI * 2))
                {
                    playerBox[0].X = (float)(2 * Math.PI) - playerBox[0].X;
                    playerBox[2].X = playerBox[0].X;
                    playerBox[1].X = playerBox[0].X + player.widthOver2 * 2;
                    playerBox[3].X = playerBox[1].X;
                }
                if (rect.boxPositionIndex == 0 && player.points[1].X < 0.0f)
                {
                    playerBox[0].X += (float)(2 * Math.PI);
                    playerBox[2].X = playerBox[0].X;
                    playerBox[1].X = playerBox[0].X + player.widthOver2 * 2;
                    playerBox[3].X = playerBox[1].X;
                }

                if (this.IntersectBoxes(rect.points, playerBox))
                {
                    //System.Diagnostics.Debugger.Break();
                    intersected = true;
                    boxIndex = i;
                    break;
                }
            }
            if (intersected)
            {
				Cube cube = obstacle.cubes[boxIndex];
				Vector3 position = new Vector3(cube.Centre.X, cube.Centre.Y, cube.Centre.Z);
				Color colour = new Color(cube.colour.X, cube.colour.Y, cube.colour.Z, 0.8f);
				emitter.CreateExplosionEmitter(position, colour, gameTime);
				logic.OnCrash();
				obstacle.RemoveCube(boxIndex);
            }
        }
		private bool PlayerStradlesOrigin()
		{
			return this.player.points[1].X < 0.0f || this.player.points[2].X > (float)(2 * Math.PI);
		}

		private bool IntersectBoxes(Vector2[] boxA, Vector2[] boxB)
		{
			bool intersected = false;
			foreach (Vector2 point in boxB)
			{
				if (point.X >= boxA[0].X && point.X <= boxA[3].X && point.Y >= boxA[0].Y && point.Y <= boxA[3].Y)
				{
					intersected = true;
					break;
				}
			}
			return intersected;
		}




		public void Update(GameTime gameTime, float playerAngle, ObstacleManager obstacle)
		{
			for (int i = 0; i < rects.Count; i++)
			{
				rects[i].points[0].Y = obstacle.cubes[i].vertices[4].Position.Z;
				rects[i].points[1].Y = obstacle.cubes[i].vertices[4].Position.Z;
				rects[i].points[2].Y = obstacle.cubes[i].vertices[0].Position.Z;
				rects[i].points[3].Y = obstacle.cubes[i].vertices[0].Position.Z;
			}
			player.Update(playerAngle);
			DoCollision(gameTime);
		}
	}
}
